/************************************************************************
 * @FileName           : softwaretimer.c
 * @Description        : 软件模拟定时器程序。
 * 		本软件定时器实现了一个向下计数自动重装载的定时器。时基通过一个硬件定时器确定。
 * 	不含有任何与底层MCU相关代码，可以移植到任何平台。定时器任务的运行可以在中断中，或
 * 	者在主函数while循环中执行。
 * 		可以使用提供的各种API函数，来修改定时器的计数值、重装载值，运行次数。可以开启
 * 	或关闭单个软件定时器。
 * @Author             : MilkLi
 * @Date               : 2021-08-10 15:27:01
 * @LastEditors        : MilkLi
 * @LastEditTime       : 2023-1-9 17:36:28
 * @MaintenanceLogbook :
/******************************************************************************/
#include "softwaretimer.h"
/* 软件定时器结构体 */
SoftwareTimerStruct SoftwareTimerList[SOFTWARE_TIMER_NUM];

/************************************************************************
 * @brief  软件定时器结构体初始化函数。可减少C51单片机中的Flash占用。
 * @author MilkLi
 * @Date   2023-1-9 17:36:18
 * @retval 无
 ************************************************************************/
void SoftwareTimer_Struct_Init(void)
{
	unsigned int n;
	
	for (n = 0; n < SOFTWARE_TIMER_NUM; n++)
	{
		SoftwareTimerList[n].id = n;
		SoftwareTimerList[n].callback = NULL;
		SoftwareTimerList[n].count = 0;
		SoftwareTimerList[n].expire = 0;
		SoftwareTimerList[n].isEnable = 0;
		SoftwareTimerList[n].repeat = 0;
		SoftwareTimerList[n].run = 0;
	}
}

/************************************************************************
 * @brief  软件定时器的时基函数，一般放在硬件定时器的中断函数中。
 * @author MilkLi
 * @Date   2021-07-10 16:35:19
 * @retval 无
 ************************************************************************/
void SoftwareTimer_Tick(void)
{
	SWT_uint8_t i = 0;
	//轮询所有的软件定时器
	for (i = 0; i < SOFTWARE_TIMER_NUM; i++)
	{
		//如果定时器未使能，则跳过。
		if (SoftwareTimerList[i].isEnable == 0)
		{
			continue;
		}
		/**
		 * @brief 为了解决初始化之后计数值为零。此时计数值不应该再减一。
		 * @EditTime 2021年11月24日17:13:44
		 *
		 */
		if (SoftwareTimerList[i].count > 0)
		{
			//软件定时器任务计数值减少
			SoftwareTimerList[i].count--;
		}
		//当软件定时器计数值为0时
		if (SoftwareTimerList[i].count == 0)
		{
			//软件定时器计数值重装载。
			SoftwareTimerList[i].count = SoftwareTimerList[i].expire;
			//软件定时器循环次数不为零
			if (SoftwareTimerList[i].repeat > 0)
			{
				SoftwareTimerList[i].repeat--;
				//将回调函数运行标志位置1
				SoftwareTimerList[i].run = 1;
			}
			//软件定时器循环次数为零
			else if (SoftwareTimerList[i].repeat == 0)
			{
				//不使能此软件定时器
				SoftwareTimerList[i].isEnable = 0;
			}
			else
			{
				//设置为无限循环时
				SoftwareTimerList[i].run = 1;
			}
		}
	}
}

/************************************************************************
 * @brief  轮询检测软件定时器任务
 * @author MilkLi
 * @Date   2021-07-10 16:34:57
 * @retval 无
 ************************************************************************/
void SoftwareTimer_Loop(void)
{
	SWT_uint8_t i = 0;
	for (i = 0; i < SOFTWARE_TIMER_NUM; i++)
	{
		//需要同时满足软件定时器使能，并且软件定时器回调函数运行标志位为1
		if (SoftwareTimerList[i].isEnable == 1 && SoftwareTimerList[i].run == 1)
		{
			SoftwareTimerList[i].run = 0;
			if (SoftwareTimerList[i].callback != NULL)
			{
				SoftwareTimerList[i].callback();
			}
		}
	}
}

/************************************************************************
 * @brief  软件定时器任务初始化函数
 * @author MilkLi
 * @Date   2021-07-10 16:33:52
 * @retval 无
 * @param  (SWT_uint8_t) id	定时器ID
 * @param  (SWT_uint32_t) count	当前定时器计数值
 * @param  (SWT_uint32_t) expire	定时器重装载值
 * @param  (timeout_handler) callback	定时器任务回调函数
 * @param  (SWT_int16_t) repeat	定时器任务回调函数运行次数
 ************************************************************************/
void SoftwareTimer_Init(SWT_uint8_t id, SWT_uint32_t count, SWT_uint32_t expire, timeout_handler callback, SWT_int16_t repeat)
{
	SoftwareTimerList[id].id = id;
	SoftwareTimerList[id].count = count;
	SoftwareTimerList[id].expire = expire;
	SoftwareTimerList[id].callback = callback;
	SoftwareTimerList[id].repeat = repeat;
	SoftwareTimerList[id].isEnable = 0;
	SoftwareTimerList[id].run = 0;
}
/************************************************************************
 * @brief  软件定时器去初始化函数
 * 		注意：若使用了此函数去初始化了某个软件定时器，那么此软件定时器将无法使用，
 * 	除非再次调用初始化函数初始化这个软件定时器
 * @author MilkLi
 * @Date   2022-02-07 16:26:15
 * @return (*)无
 * @param  (SWT_uint8_t) id 软件定时器id
 ************************************************************************/
void SoftwareTimer_Deinit(SWT_uint8_t id)
{
	SoftwareTimerList[id].count = 0;
	SoftwareTimerList[id].expire = 0;
	SoftwareTimerList[id].callback = NULL;
	SoftwareTimerList[id].repeat = 0;
	SoftwareTimerList[id].isEnable = 0;
	SoftwareTimerList[id].run = 0;
}

/************************************************************************
 * @brief  软件定时器使能
 * @author MilkLi
 * @Date   2021-07-10 16:31:54
 * @retval 无
 * @param  (SWT_uint8_t) id	需要使能的软件定时器ID
 ************************************************************************/
void SoftwareTimer_Enable(SWT_uint8_t id)
{
	SoftwareTimerList[id].isEnable = 1;
}
/************************************************************************
 * @brief  获取软件定时器使能状态
 * @author MilkLi
 * @Date   2022-02-07 16:40:35
 * @retval (SWT_uint8_t)
 * @return 软件定时器使能状态 0:未使能;1:已使能;
 * @param  (SWT_uint8_t) id 软件定时器id
 ************************************************************************/
SWT_uint8_t SoftwareTimer_Get_Enable(SWT_uint8_t id)
{
	return SoftwareTimerList[id].isEnable;
}
/************************************************************************
 * @brief  设置软件定时器使能状态
 * @author MilkLi
 * @Date   2022-02-07 16:42:56
 * @return (*)无
 * @param  (SWT_uint8_t) id 软件定时器id
 * @param  (SWT_uint8_t) able 软件定时器使能状态 0:不使能;1:使能;
 ************************************************************************/
void SoftwareTimer_Set_Enable(SWT_uint8_t id, SWT_uint8_t able)
{
	if (able != 0)
	{
		SoftwareTimerList[id].isEnable = 1;
	}
	else
	{
		SoftwareTimerList[id].isEnable = 0;
	}
}
/************************************************************************
 * @brief  软件定时器关闭
 * @author MilkLi
 * @Date   2021-07-10 16:32:56
 * @retval 无
 * @param  (SWT_uint8_t) id	需要关闭的软件定时器ID
 ************************************************************************/
void SoftwareTimer_Disable(SWT_uint8_t id)
{
	SoftwareTimerList[id].isEnable = 0;
}
/************************************************************************
 * @brief  设置定时器重装载值
 * @author MilkLi
 * @Date   2021-08-27 15:17:28
 * @retval 无
 * @param  (SWT_uint8_t) id	定时器id
 * @param  (SWT_uint32_t) expire 重装载值
 ************************************************************************/
void SoftwareTimer_Set_Expire(SWT_uint8_t id, SWT_uint32_t expire)
{
	SoftwareTimerList[id].expire = expire;
}
/************************************************************************
 * @brief  获取软件定时器重装载值
 * @author MilkLi
 * @Date   2021-08-27 15:18:40
 * @retval (SWT_uint32_t) 软件定时器的重装载值
 * @param  (SWT_uint8_t) id	软件定时器id
 ************************************************************************/
SWT_uint32_t SoftwareTimer_Get_Expire(SWT_uint8_t id)
{
	return SoftwareTimerList[id].expire;
}
/************************************************************************
 * @brief  更新软件定时器的计数值
 * 		此定时器会进入一个新的定时时间循环。
 * @author MilkLi
 * @Date   2021-08-27 15:19:44
 * @retval 无
 * @param  (SWT_uint8_t) id 软件定时器id
 ************************************************************************/
void SoftwareTimer_Reload_Count(SWT_uint8_t id)
{
	SoftwareTimerList[id].count = SoftwareTimerList[id].expire;
}
/************************************************************************
 * @brief  设置软件定时器计数值
 * @author MilkLi
 * @Date   2021-08-27 15:32:06
 * @retval 无
 * @param  (SWT_uint8_t) id 软件定时器id
 * @param  (SWT_uint32_t) count	计数值
 ************************************************************************/
void SoftwareTimer_Set_Count(SWT_uint8_t id, SWT_uint32_t count)
{
	SoftwareTimerList[id].count = count;
}
/************************************************************************
 * @brief  获取软件定时器当前计数值
 * @author MilkLi
 * @Date   2021-08-27 15:32:35
 * @retval (SWT_uint32_t) 当前计数值
 * @param  (SWT_uint8_t) id 软件定时器id
 ************************************************************************/
SWT_uint32_t SoftwareTimer_Get_Count(SWT_uint8_t id)
{
	return SoftwareTimerList[id].count;
}
/************************************************************************
 * @brief  设置软件定时器循环次数值
 * @author MilkLi
 * @Date   2022-01-27 09:54:54
 * @return (*) 无返回值
 * @param  (SWT_uint8_t) id 软件定时器idE
 * @param  (SWT_int16_t) repeat	循环次数值，如果要无限循环则需要改成FOREVER
 ************************************************************************/
void SoftwareTimer_Set_Repeat(SWT_uint8_t id, SWT_int16_t repeat)
{
	SoftwareTimerList[id].repeat = repeat;
}
/************************************************************************
 * @brief  获取软件定时器循环次数值
 * @author MilkLi
 * @Date   2022-01-27 09:55:36
 * @retval SWT_int16_t
 * @return (*) 当前剩余循环次数值
 * @param  (SWT_uint8_t) id
 ************************************************************************/
SWT_int16_t SoftwareTimer_Get_Repeat(SWT_uint8_t id)
{
	return SoftwareTimerList[id].repeat;
}
